package com.tools.web.http;

import com.tools.common.exception.IORuntimeException;
import com.tools.common.io.FileKit;
import com.tools.common.io.IOKit;
import com.tools.common.object.Note;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;

/**
 * 文件上传的包装类对象
 * */
@Note("文件上传的包装类对象")
public final class UploadFile {

    @Note("待上传文件的唯一标识")
    private String uploadKey;

    @Note("待上传的文件的名称")
    private String filename;

    @Note("待上传的文件的 MIME 类型")
    private String contentType;

    @Note("待上传字节流")
    private InputStream inputStream;

    /* **************************************************************************************
     *
     *          构造器
     *
     * **************************************************************************************
     * */

    public UploadFile(String uploadKey, String filename, InputStream inputStream) {
        this.setUploadKey(uploadKey);
        this.setFilename(filename);
        this.setInputStream(inputStream);
    }

    public UploadFile(String uploadKey, String filename, String contentType, InputStream inputStream) {
        this.setUploadKey(uploadKey);
        this.setFilename(filename);
        this.setContentType(contentType);
        this.setInputStream(inputStream);
    }

    public UploadFile(String uploadKey, File file) {
        if(file == null) throw new NullPointerException("待上传的文件不能为 null");
        this.setUploadKey(uploadKey);
        this.setFilename(file.getName());
        this.setInputStream(IOKit.fileInputStream(file));
    }

    public UploadFile(String uploadKey, File file, String contentType) {
        if(file == null) throw new NullPointerException("待上传的文件不能为 null");
        this.setUploadKey(uploadKey);
        this.setFilename(file.getName());
        this.setContentType(contentType);
        this.setInputStream(IOKit.fileInputStream(file));
    }

    public UploadFile(MultipartFile multipartFile) {
        if(multipartFile == null) throw new NullPointerException("待上传的文件不能为 null");
        this.setUploadKey(multipartFile.getName());
        this.setFilename(multipartFile.getOriginalFilename());
        this.setContentType(multipartFile.getContentType());
        try {
            this.setInputStream(multipartFile.getInputStream());
        } catch (IOException e) {
            throw new IORuntimeException(e);
        }
    }

    public static UploadFile of(String uploadKey, String filename, InputStream inputStream) {
        return new UploadFile(uploadKey, filename, inputStream);
    }

    public static UploadFile of(String uploadKey, String filename, String contentType, InputStream inputStream) {
        return new UploadFile(uploadKey, filename, contentType, inputStream);
    }

    public static UploadFile of(String uploadKey, File file) {
        return new UploadFile(uploadKey, file);
    }

    public static UploadFile of(String uploadKey, File file, String contentType) {
        return new UploadFile(uploadKey, file, contentType);
    }

    public static UploadFile of(MultipartFile multipartFile) {
        return new UploadFile(multipartFile);
    }

    /* **************************************************************************************
     *
     *          Getter / Setter
     *
     * **************************************************************************************
     * */

    public String getUploadKey() {
        return uploadKey;
    }

    public void setUploadKey(String uploadKey) {
        if(uploadKey == null || uploadKey.isEmpty()) throw new NullPointerException("待上传的文件的 key 不能为空");
        this.uploadKey = uploadKey;
    }

    public String getFilename() {
        return filename;
    }

    public void setFilename(String filename) {
        if(filename == null || filename.isEmpty()) throw new NullPointerException("待上传的文件的文件名称不能为空");
        this.filename = filename;
    }

    public String getContentType() {
        return (contentType == null) ? FileKit.getMimeType(filename) : contentType;
    }

    public void setContentType(String contentType) {
        if(contentType == null || contentType.isEmpty()) throw new NullPointerException("待上传的文件的 MIME 类型不能为空");
        if(contentType.indexOf('/') == -1) {
            throw new IllegalArgumentException("上传的 MIME 类型有误");
        }
        this.contentType = contentType;
    }

    public InputStream getInputStream() {
        return inputStream;
    }

    public void setInputStream(InputStream inputStream) {
        if(inputStream == null) throw new NullPointerException("不能设置 null 的文件上传到网络");
        this.inputStream = inputStream;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UploadFile that = (UploadFile) o;
        return Objects.equals(uploadKey, that.uploadKey);
    }

    @Override
    public int hashCode() {
        return Objects.hash(uploadKey);
    }

    @Override
    public String toString() {
        return "UploadFile{" +
                "uploadKey='" + uploadKey + '\'' +
                ", filename='" + filename + '\'' +
                ", contentType='" + contentType + '\'' +
                ", inputStream=" + inputStream +
                '}';
    }

    /* **************************************************************************************
     *
     *          链式方法
     *
     * **************************************************************************************
     * */

    public UploadFile uploadKey(String uploadKey) {
        this.setUploadKey(uploadKey);
        return this;
    }


    public UploadFile filename(String filename) {
        this.setFilename(filename);
        return this;
    }

    public UploadFile contentType(String contentType) {
        this.setContentType(contentType);
        return this;
    }

    public UploadFile inputStream(InputStream inputStream) {
        this.setInputStream(inputStream);
        return this;
    }
}
